package com.gladlee.myACP;

//import static java.lang.System.*;
//import static com.gladlee.myACP.tool.myAtomTool.*;
import static com.gladlee.ACP.tool.AtomTool.getLocalIP;
import static com.gladlee.ACP.tool.AtomTool.getSubByteArray;
import static com.gladlee.myACP.tool.myAtomTool.getBytes;
import static com.gladlee.myACP.tool.myAtomTool.getDouble;
import static com.gladlee.myACP.tool.myAtomTool.getInt;
import static com.gladlee.myACP.tool.myAtomTool.getString;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.gladlee.ACP.Atom;
import com.gladlee.ACP.AtomUser;
import com.gladlee.ACP.tool.AtomTool;

public class myAtomUser extends AtomUser {
	// protected
	protected boolean sendFlag=true;
	protected boolean receiveFlag=true;
	public String[] ccArray = { "ACPower", "ACVoltage", "ACCurrent",
			"ACStation", "ACTemperature", "ACFlow", "ACWindDirection",
			"ACWindStation", "ACTimeOn", "ACTimeOff", "ACBrand",
			"ContextualModel", "Time", "IPs" ,"SendPeriod"};
	public String[] ccInt = { "ACStation", "ACFlow", "ACWindStation",
			"ACTimeOn", "ACTimeOff", "ACTimeOn" };
	public String[] ccDouble = { "ACPower", "ACVoltage", "ACCurrent",
			"ACTemperature", "ACWindDirection" };
	public String[] ccString = { "ACBrand", "ContextualModel" };
	protected byte[] b_f1 = { 0x11 };
	protected byte[] b_f2 = { 0x77 };
	protected byte[] b_length = new byte[2];
	protected int p_f1 = 0;
	protected int p_cc = 1;
	protected int p_sa = 33;
	protected int p_c = 37;
	protected int p_length = 38;
	protected int p_data = 40;
	protected int p_crc_r;
	protected int p_f2_r;
	protected int p_crc_s;
	protected int p_f2_s;
	protected final int l_f1 = 1;
	protected final int l_cc = 32;
	protected final int l_sa = 4;
	protected final int l_c = 1;
	protected final int l_length = 2;
	protected int l_data_s;
	protected int l_data_r;
	protected final int l_crc = 1;
	protected final int l_f2 = 1;
	protected int bufferSize = 8192;
	protected String encoding = "UTF-8";
	@Override
	public void endSend(){
		this.sendFlag=false;
	}
	@Override
	public  void endReceive(){
		this.receiveFlag=false;
	}
	@SuppressWarnings("unchecked")
	@Override
	protected void init() {
		File file = new File("conf/" + this.configFileName);
		if(file.exists()){
			SAXReader reader = new SAXReader();
			Document doc;
			try {
				doc = reader.read(file);
				List<Node> ip_nodes = doc.selectNodes("//ips/ip");
				Iterator<Node> it = ip_nodes.iterator();
				while (it.hasNext()) {
					Node node = (Node) it.next();
					this.ipSet.add(node.getText());
				}
				Node st_node=doc.selectSingleNode("//sendPeriod");
				sendPeriod=Integer.valueOf(st_node.getText());
			} catch (DocumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else{
			System.out.println("配置文件不存在~");
		}
		
	}

	public myAtomUser() {
		super();
		init();
		p_cc = p_f1 + l_f1;
		p_sa = p_cc + l_cc;
		p_c = p_sa + l_sa;
		p_length = p_c + l_c;
		p_data = p_length + l_length;
		// ipSet.add("59.66.136.255");
	}

	public myAtomUser(Atom a) {
		this();
		atom = a;
	}

	public void setAtom(Atom a) {
		atom = a;
	}

	protected String getContentCode(byte[] buffer) {
		if (isContentCode(buffer)) {
			return new String(new String(buffer).trim());
		} else {
			return null;
		}
	}

	private boolean isContentCode(byte[] cc_r) {
		String cc_s = new String(cc_r).trim();
		for (int i = 0; i < this.ccArray.length; i++) {
			if (cc_s.equalsIgnoreCase(ccArray[i])) {
				return true;
			}
		}
		return false;
	}

	@Override
	public int getIntData(String cc, Map<String, byte[]> map) {
		int r = 0;
		byte[] byteData = map.get(cc);
		r = getInt(byteData);
		return r;
	}

	@Override
	public byte getByteData(String cc, Map<String, byte[]> map) {
		// TODO Auto-generated method stub
		byte r = 0;
		byte[] byteData = map.get(cc);
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(
				byteData));
		try {
			r = dis.readByte();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return r;
	}

	@Override
	public boolean getBooleanData(String cc, Map<String, byte[]> map) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public float getFloatData(String cc, Map<String, byte[]> map) {
		// TODO Auto-generated method stub
		float r = 0;
		byte[] byteData = map.get(cc);
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(
				byteData));
		try {
			r = dis.readFloat();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return r;
	}

	@Override
	public double getDoubleData(String cc, Map<String, byte[]> map) {
		double r = 0;
		byte[] byteData = map.get(cc);
		r = getDouble(byteData);
		// r=Double.longBitsToDouble(bits);
		return r;
	}

	@Override
	public char getCharData(String cc, Map<String, byte[]> map) {
		char r = 0;
		byte[] byteData = map.get(cc);
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(
				byteData));
		try {
			r = dis.readChar();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return r;
	}

	@Override
	public String getStringData(String cc, Map<String, byte[]> map) {
		String r = null;
		byte[] byteData = map.get(cc);
		r = getString(byteData);
		return r;

	}

	@Override
	public void send() {
		try {
			Map<String, byte[]> ADF = atom.getADFOut();
			byte[] buffer;
			DatagramPacket dp = null;
			DatagramSocket ds = atom.getSocket();
			while (sendFlag) {
				Thread.sleep(sendPeriod);
				Set<String> set = ADF.keySet();
				Iterator<String> it = set.iterator();
				while (it.hasNext()) {
					if(!sendFlag){
						break;
					}
					String cc = it.next();
					byte[] data = ADF.get(cc);
					buffer = encode(cc, data);
					Iterator<String> it_ip = ipSet.iterator();
					dp = new DatagramPacket(buffer, buffer.length);
					dp.setPort(atom.getPort());
					while (it_ip.hasNext()) {
						if(!sendFlag){
							break;
						}
						InetAddress ip=InetAddress.getByName(it_ip.next());
						dp.setAddress(ip);
						ds.send(dp);
//						System.out.println(new String(data));
					}
				}
			}
		} catch (Exception e) {
			System.out.println("sendFlag:"+receiveFlag);
			e.printStackTrace();
		}
	}

	protected byte[] encode(String cc, byte[] data) {
		l_data_s = data.length;
		p_crc_s = p_data + l_data_s;
		p_f2_s = p_crc_s + l_crc;
		int tl = l_f1 + l_cc + l_sa + l_c + l_length + l_data_s + l_crc + l_f2;
		byte[] m = new byte[tl];
		byte[] b_CC = null;
		byte[] b_SA = new byte[4];
		byte[] b_C = new byte[l_c];
		byte crc = 0;
		b_length[0] = (byte) ((l_data_s & 0xff00) >> 8);
		b_length[1] = (byte) (l_data_s & 0xff);
		String s_SA = getLocalIP();
		String[] s_array_SA = s_SA.split("\\.");

		for (int i = 0; i < 4; i++) {
			b_SA[i] = Integer.valueOf(s_array_SA[i]).byteValue();
		}
		b_CC = cc.getBytes();
		for (int i = p_f1; i < l_f1; i++) {
			m[i] = b_f1[i - p_f1];
		}
		for (int i = p_cc; i < p_cc + l_cc; i++) {
			if (i - p_cc < b_CC.length) {
				m[i] = b_CC[i - p_cc];
				crc += m[i];
			} else {
				m[i] = 0;
			}
		}
		for (int i = p_sa; i < p_sa + l_sa; i++) {
			m[i] = b_SA[i - p_sa];
			crc += m[i];
		}
		for (int i = p_c; i < p_c + l_c; i++) {
			m[i] = b_C[i - p_c];
			crc += m[i];
		}
		for (int i = p_length; i < p_length + l_length; i++) {
			m[i] = b_length[i - p_length];
			crc += m[i];
		}
		for (int i = p_data; i < p_data + l_data_s; i++) {
			m[i] = data[i - p_data];
			crc += m[i];
		}
		m[p_crc_s] = crc;
		for (int i = p_f2_s; i < p_f2_s + l_f2; i++) {
			m[i] = b_f2[i - p_f2_s];
		}
		return m;
	}

	protected void decode(byte[] buffer) throws UnsupportedEncodingException {
		if (buffer.length < l_f1 + l_f2 + l_cc + l_sa + l_c + l_length + l_crc) {
			return;
		}
		for (int i = p_f1; i < p_f1 + l_f1; i++) {
			if (buffer[i] != b_f1[i - p_f1]) {
				return;
			}
		}
		byte[] cc_array = getSubByteArray(buffer, p_cc, 32);
		String cc = getContentCode(cc_array);
		if (cc == null) {
			return;
		}
		byte lh = buffer[p_length];
		byte ll = buffer[p_length + 1];
		int l = (getInt(lh) << 8) + getInt(ll);
		p_crc_r = p_data + l;
		p_f2_r = p_crc_r + l_crc;
		byte[] data = new byte[l];
		for (int i = p_data; i < p_data + l; i++) {
			data[i - p_data] = buffer[i];
		}
		int num_crc = l_cc + l_sa + l_c + l_length + l;
		byte crc = 0;
		for (int i = p_cc; i < p_cc + num_crc; i++) {
			crc += buffer[i];
		}
		if (crc != buffer[p_crc_r]) {
			return;
		}
		for (int i = p_f2_r; i < p_f2_r + l_f2; i++) {
			if (buffer[i] != b_f2[i - p_f2_r]) {
				return;
			}
		}
		if (cc.equalsIgnoreCase("IPs")) {
			if (ipSet.add(new String(data))) {
				String s = new String(data);
				System.out.println(s);
			}
		}
		if(cc.equalsIgnoreCase("time")){
			System.out.println("收到数据："+new String(data,"UTF-8"));
		}
		if(cc.equalsIgnoreCase("sendPeriod")){
			setSendPeriod(getInt(data));
		}
		atom.getADFIn().put(cc, data);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.gladlee.ACP.AtomUser#receive()
	 * DatagramPakcet.getLength()返回读取到的长度 getData()返回绑定的字节数
	 */
	@Override
	public void receive() {
		DatagramSocket ds = atom.getSocket();
		try {
			byte[] buffer = new byte[bufferSize];
			DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
			while (receiveFlag) {
				ds.receive(dp);
				byte[] byte_data = AtomTool.getSubByteArray(dp.getData(), 0,
						dp.getLength());
				decode(byte_data);
			}
		} catch (Exception e) {
			System.out.println("receiveFlag:"+receiveFlag);
			System.out.println("receive failed");
//			e.printStackTrace();
		}
	}

	@Override
	public void putIntData(String cc, int data) {
		putData(cc, getBytes(data));
	}

	@Override
	public void putDoubleData(String cc, double data) {
		putData(cc, getBytes(data));
	}

	@Override
	public void putStringData(String cc, String data) {
		try {
			putData(cc, getBytes(data));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void putData(String cc, byte[] data) {
		atom.getADFOut().put(cc, data);
	}
}
